package com.gitee.l0km.xthrift.thrift.codec;

import java.util.Map;

import org.apache.thrift.protocol.TProtocol;

import com.facebook.swift.codec.ThriftCodec;
import com.facebook.swift.codec.internal.builtin.MapThriftCodec;
import com.facebook.swift.codec.metadata.ThriftType;
import com.gitee.l0km.xthrift.thrift.protocol.TProtocolReaderXthrift;
import com.gitee.l0km.xthrift.thrift.protocol.TProtocolWriterXthrift;
import com.gitee.l0km.xthrift.thrift.reflection.FieldSupport;
import com.google.common.base.Preconditions;

/**
 * 重写{@link #read(TProtocol)},{@link #write(Map, TProtocol)}方法,
 * 使用{@link TProtocolWriterXthrift},{@link TProtocolReaderXthrift}替代原生的{@code TProtocolReader,TProtocolWriter}
 * @author guyadong
 *
 * @param <K>
 * @param <V>
 * @since 1.5.0
 */
public class MapThriftCodecXthrift<K, V> extends MapThriftCodec<K, V> {
	private final ThriftCodec<K> keyCodec;
	private final ThriftCodec<V> valueCodec;

	private MapThriftCodecXthrift(ThriftType type, ThriftCodec<K> keyCodec, ThriftCodec<V> valueCodec) {
		super(type, keyCodec, valueCodec);
		this.keyCodec = keyCodec;
		this.valueCodec = valueCodec;
	}

	@Override
	public Map<K, V> read(TProtocol protocol) throws Exception {
		return TProtocolReaderXthrift.of(protocol).readMap(keyCodec, valueCodec);
	}

	@Override
	public void write(Map<K, V> value, TProtocol protocol) throws Exception {
		Preconditions.checkNotNull(value, "value is null");
		TProtocolWriterXthrift.of(protocol).writeMap(keyCodec, valueCodec, value);
	}

	/**
	 * 如果是Map类型编解码器则替换为自定义的{@link MapThriftCodecXthrift}实例以支持不带类型的标准JSON格式数据协议 
	 * @param <T>
	 * @param codec
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static <T> ThriftCodec<T> usingIfMap(ThriftCodec<T> codec) {
		if ((codec instanceof MapThriftCodec) && !(codec instanceof MapThriftCodecXthrift)) {
			return (ThriftCodec<T>) new MapThriftCodecXthrift(codec.getType(),
					FieldSupport.<ThriftCodec>fieldValueOf(codec, "keyCodec"),
					FieldSupport.<ThriftCodec>fieldValueOf(codec, "valueCodec"));
		}
		return codec;
	}
}
